﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RayDen.Library.Core.Primitives;
using RayDen.RayEngine.Core;
using RayDen.RayEngine.Core.Devices;
using RayDen.RayEngine.Core.Interface;
using RayDen.RayEngine.Core.Threads;
using RayDen.RayEngine.Managers;
using RayDen.RayEngine.Samplers;

namespace RayDen.RayEngine
{
    public class EngineTemplate<TPathSampler, TSampler, TPathBuffer, TFilm>
        where TPathSampler : PathSamplerBase, new()
        where TSampler : ISampler
        where TFilm:ImageFilm<TPathSampler>
        where TPathBuffer : PathBuffer<TPathSampler>, new()
    {
        public abstract class Engine : BaseRenderingEngine
        {
            public Engine(RayEngineScene scene)
                : base(scene)
            {
                GlobalConfiguration.Instance.SpectralRendering = false;
            }

            public override RenderThread CreateRenderThread(int threadIndex, IntersectionEngine intersectionDevice, RayEngineScene scene, IImageFilm film, IFrameManager frameManager, SamplingContext samplingContext)
            {
                return new DeviceRenderThread<TPathBuffer>(threadIndex, intersectionDevice, scene,
                                                                        LowLatencySampling, film, samplingContext
                                                                        , frameManager);
            }

            public override ISampler CreateSampler(int width, int height, int maxPathDepth, int threadIndex, int screenStartLine, int windowHeight)
            {
                var sampler = new UniformSampler()
                    {
                        lowLatency = LowLatencySampling,
                        tIdx = threadIndex,
                        screenWidth = width,
                        screenHeight = height,
                        screenStartLine = screenStartLine
                    };
                return sampler;
            }


            public override Core.Interface.IImageFilm CreateFilm(int width, int height)
            {
                return this.CreateFilmInternal(width, height);
            }

            protected abstract TFilm CreateFilmInternal(int width, int height);

        }
    }   
}
